package com.zgjkhis.modules.system.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zgjkhis.common.service.impl.BaseServiceImpl;
import com.zgjkhis.common.utils.QueryHelpPlus;
import com.zgjkhis.modules.charges.service.dto.InfoDto;
import com.zgjkhis.modules.his.service.dto.DataPrescription;
import com.zgjkhis.modules.his.service.dto.DataPrescriptionDetail;
import com.zgjkhis.modules.system.domain.Info;
import com.zgjkhis.modules.system.domain.InfoSalesDate;
import com.zgjkhis.modules.system.domain.InfoSalesDoc;
import com.zgjkhis.modules.system.domain.Store;
import com.zgjkhis.modules.system.domain.vo.InfoMarketHomeSaleVo;
import com.zgjkhis.modules.system.domain.vo.InfoMarketTopSaleVo;
import com.zgjkhis.modules.system.domain.vo.InfoSaleVo;
import com.zgjkhis.modules.system.service.*;
import com.zgjkhis.modules.system.service.mapper.InfoMapper;
import com.zgjkhis.utils.FileUtil;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

// 默认不使用缓存
//import org.springframework.cache.annotation.CacheConfig;
//import org.springframework.cache.annotation.CacheEvict;
//import org.springframework.cache.annotation.Cacheable;

/**
 * @Author yzq
 * @Description 处方
 * @Date 2021/6/23 9:47
 * @Param
 * @return
 **/
@Service
@AllArgsConstructor
//@CacheConfig(cacheNames = "user")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class InfoServiceImpl extends BaseServiceImpl<InfoMapper, Info> implements InfoService {

    private final InfoDrugService infoDrugService;
    private final InfoSalesDocService infoSalesDocService;
    private final InfoSalesDateService infoSalesDateService;
    private final StoreService storeService;

    @Override
    public List<DataPrescription> queryDataList() {
        return infoDrugService.queryDataList();
    }

    @Override
    public List<DataPrescriptionDetail> queryDataDetailList(String id, BigDecimal quantityDay) {
        return infoDrugService.queryDataDetailList(id,quantityDay);
    }

    @Override
    public List<InfoDto> queryListByOrderNo(String orderNo) {
        return baseMapper.queryListByOrderNo(orderNo);
    }

    @Override
    public List<DataPrescription> queryInfoByOrderNo(String orderNo) {
        return infoDrugService.queryInfoByOrderNo(orderNo);
    }

    @Override
    public List<InfoSaleVo> infoStatistics(String pharmacyId, String startDate, String endDate, String docName,String historyType) {
        String type="doc";
        if("1".equals(historyType)){
            List<InfoSaleVo> infoSaleVos = infoSalesDocService.findAllByDate(pharmacyId,startDate,endDate);
            return infoSaleVos;
        }else{
            List<InfoSaleVo> infoSaleVos=baseMapper.infoStatistics(pharmacyId,startDate,endDate,type,docName);
            List<InfoSaleVo> infoRefundStatistics=baseMapper.infoRefundStatistics(pharmacyId,startDate,endDate,type);

            HashMap<String, InfoSaleVo> map = new HashMap<>();
            for (InfoSaleVo vo : infoRefundStatistics) {
                map.put(vo.getDocId(), vo);
            }
            for(InfoSaleVo infoSaleVo:infoSaleVos){
                InfoSaleVo refund=map.get(infoSaleVo.getDocId());
                if(refund!=null){
                    infoSaleVo.setKljPayInfoFee(infoSaleVo.getKljAllInfoFee().subtract(refund.getKljRefundFee()));
                    infoSaleVo.setYpPayInfoFee(infoSaleVo.getYpAllInfoFee().subtract(refund.getYpRefundFee()));
                    infoSaleVo.setXyPayInfoFee(infoSaleVo.getXyAllInfoFee().subtract(refund.getXyRefundFee()));
                    infoSaleVo.setRefundFee(refund.getRefundFee());
                    infoSaleVo.setPayFee(infoSaleVo.getAllFee().subtract(refund.getRefundFee()));
                }else {
                    infoSaleVo.setKljPayInfoFee(infoSaleVo.getKljAllInfoFee());
                    infoSaleVo.setYpPayInfoFee(infoSaleVo.getYpAllInfoFee());
                    infoSaleVo.setXyPayInfoFee(infoSaleVo.getXyAllInfoFee());
                    infoSaleVo.setPayFee(infoSaleVo.getAllFee());

                }
            }
            return infoSaleVos;

        }
    }

    @Override
    public InfoMarketHomeSaleVo infoSalesDate(String pharmacyId, String startDate, String endDate,String historyType) {
        InfoMarketHomeSaleVo infoMarketHomeSaleVo = new InfoMarketHomeSaleVo();
        String type="date";
        String docName=null;
        List<InfoSaleVo> infoSaleVos = new ArrayList<>();

        if("1".equals(historyType)){
            infoSaleVos = infoSalesDateService.findAllByDate(pharmacyId,startDate,endDate);
        }else {
            infoSaleVos = baseMapper.infoStatistics(pharmacyId, startDate, endDate, type, docName);
            List<InfoSaleVo> infoRefundStatistics = baseMapper.infoRefundStatistics(pharmacyId, startDate, endDate, type);
            List<InfoSaleVo> infoDrugCostStatistics = baseMapper.infoDrugCostStatistics(pharmacyId, startDate, endDate, type);

            HashMap<String, InfoSaleVo> map = new HashMap<>();
            for (InfoSaleVo vo : infoRefundStatistics) {
                map.put(vo.getDate(), vo);
            }
            HashMap<String, InfoSaleVo> mapCost = new HashMap<>();
            for (InfoSaleVo vo : infoDrugCostStatistics) {
                mapCost.put(vo.getDate(), vo);
            }
            for (InfoSaleVo infoSaleVo : infoSaleVos) {
                InfoSaleVo refund = map.get(infoSaleVo.getDate());
                if (refund != null) {
                    infoSaleVo.setKljPayInfoFee(infoSaleVo.getKljAllInfoFee().subtract(refund.getKljRefundFee()));
                    infoSaleVo.setYpPayInfoFee(infoSaleVo.getYpAllInfoFee().subtract(refund.getYpRefundFee()));
                    infoSaleVo.setXyPayInfoFee(infoSaleVo.getXyAllInfoFee().subtract(refund.getXyRefundFee()));
                } else {
                    infoSaleVo.setKljPayInfoFee(infoSaleVo.getKljAllInfoFee());
                    infoSaleVo.setYpPayInfoFee(infoSaleVo.getYpAllInfoFee());
                    infoSaleVo.setXyPayInfoFee(infoSaleVo.getXyAllInfoFee());
                }

                InfoSaleVo cost = mapCost.get(infoSaleVo.getDate());
                if (cost != null) {
                    infoSaleVo.setXyCost(cost.getXyCost());
                    infoSaleVo.setYpCost(cost.getYpCost());
                    infoSaleVo.setKljCost(cost.getKljCost());
                    infoSaleVo.setXyProfit(infoSaleVo.getXyPayInfoFee().subtract(cost.getXyCost()));
                    infoSaleVo.setYpProfit(infoSaleVo.getYpPayInfoFee().subtract(cost.getYpCost()));
                    infoSaleVo.setKljProfit(infoSaleVo.getKljPayInfoFee().subtract(cost.getKljCost()));
                }
            }
        }
        infoMarketHomeSaleVo.setInfoSaleVoList(infoSaleVos);
        infoMarketHomeSaleVo.setXyInfoNum(infoSaleVos.stream().collect(Collectors.summingInt(InfoSaleVo::getXyInfoNum)));
        infoMarketHomeSaleVo.setYpInfoNum(infoSaleVos.stream().collect(Collectors.summingInt(InfoSaleVo::getYpInfoNum)));
        infoMarketHomeSaleVo.setKljInfoNum(infoSaleVos.stream().collect(Collectors.summingInt(InfoSaleVo::getKljInfoNum)));
        infoMarketHomeSaleVo.setXyPayInfoNum(infoSaleVos.stream().collect(Collectors.summingInt(InfoSaleVo::getXyPayInfoNum)));
        infoMarketHomeSaleVo.setYpPayInfoNum(infoSaleVos.stream().collect(Collectors.summingInt(InfoSaleVo::getYpPayInfoNum)));
        infoMarketHomeSaleVo.setKljPayInfoNum(infoSaleVos.stream().collect(Collectors.summingInt(InfoSaleVo::getKljPayInfoNum)));
        infoMarketHomeSaleVo.setXyPayInfoFee(infoSaleVos.stream().map(InfoSaleVo::getXyPayInfoFee).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setYpPayInfoFee(infoSaleVos.stream().map(InfoSaleVo::getYpPayInfoFee).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setKljPayInfoFee(infoSaleVos.stream().map(InfoSaleVo::getKljPayInfoFee).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setXyCost(infoSaleVos.stream().map(InfoSaleVo::getXyCost).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setYpCost(infoSaleVos.stream().map(InfoSaleVo::getYpCost).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setKljCost(infoSaleVos.stream().map(InfoSaleVo::getKljCost).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setXyProfit(infoSaleVos.stream().map(InfoSaleVo::getXyProfit).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setYpProfit(infoSaleVos.stream().map(InfoSaleVo::getYpProfit).reduce(BigDecimal.ZERO, BigDecimal::add));
        infoMarketHomeSaleVo.setKljProfit(infoSaleVos.stream().map(InfoSaleVo::getKljProfit).reduce(BigDecimal.ZERO, BigDecimal::add));
        return infoMarketHomeSaleVo;
    }


    @Override
    public InfoMarketTopSaleVo infoMarketTop(String pharmacyId) {
        return baseMapper.infoMarketTop(pharmacyId);
    }

    @Override
    public void dayPigeonhole(String date) {
        QueryWrapper criteria = new QueryWrapper();
        List<Store> stores = storeService.list(QueryHelpPlus.getPredicate(Store.class, criteria));
        for(Store store:stores) {
            String pharmacyId =String.valueOf(store.getId());
            String docName = null;
            String historyType = null;

            if (date == null || date.isEmpty()) {
                DateTime dateTime = DateUtil.offset(new Date(), DateField.DAY_OF_MONTH, -7);
                date = DateUtil.formatDate(dateTime);
            }
            Date pigeonholeTime = DateUtil.parseDate(date);
            // 清理当天的归档记录
            this.clearPigeonhole(pigeonholeTime);
            // 开始归档
            // PigeonholeParam param = new PigeonholeParam(date + " 00:00:00", date + " 23:59:59");
            String startDate = date + " 00:00:00";
            String endDate = date + " 23:59:59";
            List<InfoSaleVo> statisticsList = infoStatistics(pharmacyId, startDate, endDate, docName, historyType);
            if (statisticsList == null || statisticsList.isEmpty()) {
                return;
            }
            statisticsList.forEach(item -> {
                InfoSalesDoc infoSalesDoc = new InfoSalesDoc();
                BeanUtils.copyProperties(item, infoSalesDoc);
                infoSalesDoc.setCreateTime(new Date());
                infoSalesDoc.setDate(pigeonholeTime);
                infoSalesDoc.setPharmacyId(pharmacyId);
                infoSalesDocService.save(infoSalesDoc);
            });
            InfoMarketHomeSaleVo vo = infoSalesDate(pharmacyId, startDate, endDate, historyType);
            List<InfoSaleVo> infoSaleVoList = vo.getInfoSaleVoList();
            if (infoSaleVoList == null || infoSaleVoList.isEmpty()) {
                return;
            }
            infoSaleVoList.forEach(item -> {
                InfoSalesDate infoSalesDoc = new InfoSalesDate();
                BeanUtils.copyProperties(item, infoSalesDoc);
                infoSalesDoc.setCreateTime(new Date());
                infoSalesDoc.setDate(pigeonholeTime);
                infoSalesDoc.setPharmacyId(pharmacyId);
                infoSalesDoc.setIsDel(0);
                infoSalesDateService.save(infoSalesDoc);
            });
        }
    }

    /**
     * 清理归档记录
     * 出错自动修复
     * @param pigeonholeTime
     */
    private void clearPigeonhole(Date pigeonholeTime) {
        LambdaQueryWrapper<InfoSalesDoc> wrapper =  Wrappers.lambdaQuery();
        wrapper.eq(InfoSalesDoc::getDate, pigeonholeTime);
        infoSalesDocService.remove(wrapper);
        LambdaQueryWrapper<InfoSalesDate> wrappers =  Wrappers.lambdaQuery();
        wrappers.eq(InfoSalesDate::getDate, pigeonholeTime);
        infoSalesDateService.remove(wrappers);
    }




    @Override
    public void outInfoSalesDate(String pharmacyId, String startDate, String endDate,String docName,String historyType, HttpServletResponse response) throws IOException {

        InfoMarketHomeSaleVo  infoMarketHomeSaleVo = infoSalesDate(pharmacyId,startDate,endDate,historyType);
        List<InfoSaleVo> statisticsList=infoMarketHomeSaleVo.getInfoSaleVoList();
        List<Map<String, Object>> list = new ArrayList<>();
        for (InfoSaleVo vo : statisticsList) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("日期",vo.getDate());
            map.put("西药及中成药成方数",vo.getXyPayInfoNum());
            map.put("西药及中成药开方数",vo.getXyInfoNum() );
            map.put("西药及中成药销售额",vo.getXyPayInfoFee() );
            map.put("西药及中成药成本",vo.getXyCost());
            map.put("西药及中成药利润",vo.getXyProfit() );
            map.put("中药饮片成方数",vo.getYpPayInfoNum() );
            map.put("中药饮片开方数",vo.getYpInfoNum() );
            map.put("中药饮片销售额",vo.getYpPayInfoFee() );
            map.put("中药饮片成本",vo.getYpCost() );
            map.put("中药饮片利润",vo.getYpProfit() );
            map.put("颗粒剂成方数", vo.getKljPayInfoNum());
            map.put("颗粒剂开方数",vo.getKljInfoNum() );
            map.put("颗粒剂销售额",vo.getKljPayInfoFee() );
            map.put("颗粒剂成本",vo.getKljCost() );
            map.put("颗粒剂利润",vo.getKljProfit() );
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void outInfoSalesDoc(String pharmacyId, String startDate, String endDate,String docName,String historyType, HttpServletResponse response) throws IOException {

        List<InfoSaleVo> statisticsList = infoStatistics(pharmacyId,startDate,endDate,docName,historyType);
        List<Map<String, Object>> list = new ArrayList<>();
        for (InfoSaleVo vo : statisticsList) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("医生姓名",vo.getDocName());
            map.put("西药及中成药成方数",vo.getXyPayInfoNum());
            map.put("西药及中成药开方数",vo.getXyInfoNum() );
            map.put("西药及中成药销售额",vo.getXyPayInfoFee() );
            map.put("中药饮片成方数",vo.getYpPayInfoNum() );
            map.put("中药饮片开方数",vo.getYpInfoNum() );
            map.put("中药饮片销售额",vo.getYpPayInfoFee() );
            map.put("颗粒剂成方数", vo.getKljPayInfoNum());
            map.put("颗粒剂开方数",vo.getKljInfoNum() );
            map.put("颗粒剂销售额",vo.getKljPayInfoFee() );
            map.put("总成方数", vo.getPayInfoNum());
            map.put("总开方数",vo.getAllInfoNum() );
            map.put("总销售额",vo.getPayFee() );
            map.put("总退方数", vo.getRefundInfoNum());
            map.put("总退方金额",vo.getRefundFee() );
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}
